namespace Bowlus.AppHost
{
    using System;
    using System.Diagnostics;
    using System.Linq;
    using System.Reactive.Concurrency;

    using Bowlus.Common;

    using Microsoft.Practices.Unity;
    using Microsoft.WindowsAzure;
    using Microsoft.WindowsAzure.Diagnostics;
    using Microsoft.WindowsAzure.ServiceRuntime;
    using System.Reactive.Linq;

    public class WebRole : RoleEntryPoint
    {
        private AppHostManager appHostManager;
        private readonly IObservable<long> _checkStateTimer;

        public WebRole()
            : base()
        {
            this._checkStateTimer = Observable.Interval(Settings.TenantTablePollingInterval);
        }

        public override bool OnStart()
        {
            ConfigureDiagnostics();

            RoleEnvironment.Changing += RoleEnvironmentChanging;

            try
            {
                BowlusLogger.LogInfo("Starting apphost web role.");
                var unityContainer = BowlusContainer.Current.GetInstance<IUnityContainer>();
                ContainerBootstrapper.RegisterTypes(unityContainer);
                this.appHostManager = unityContainer.Resolve(typeof(AppHostManager)) as AppHostManager;

                BowlusLogger.LogInfo("Resolved AppHostManager.");
                Debug.Assert(this.appHostManager != null, "deploymentManager != null");

                this.appHostManager.Initialize();
                BowlusLogger.LogInfo("Apphost web role started.");
            }
            catch (Exception exception)
            {
                BowlusLogger.LogError(string.Format("Error while initializing the deployment manager. {0}", exception));
            }

            return base.OnStart();
        }

        public override void Run()
        {
            this._checkStateTimer.Subscribe(s => this.appHostManager.Run());
            base.Run();
        }

        private static void RoleEnvironmentChanging(object sender, RoleEnvironmentChangingEventArgs e)
        {
            if (e.Changes.Any(change => change is RoleEnvironmentConfigurationSettingChange))
            {
                e.Cancel = e.Changes.OfType<RoleEnvironmentConfigurationSettingChange>().Any(Settings.ShouldRecycleInstance);
            }
            else if (e.Changes.Any(change => change is RoleEnvironmentTopologyChange))
            {
                e.Cancel = false;
            }
        }

        private static void ConfigureDiagnostics()
        {
            var config = DiagnosticMonitor.GetDefaultInitialConfiguration();

            CrashDumps.EnableCollection(true);

            config.DiagnosticInfrastructureLogs.ScheduledTransferPeriod = TimeSpan.FromMinutes(1);

            // For windows azure logs
            config.Logs.ScheduledTransferPeriod = TimeSpan.FromMinutes(1);
            config.Logs.ScheduledTransferLogLevelFilter = LogLevel.Verbose;

            var cloudStorageAccount = CloudStorageAccount.Parse(RoleEnvironment.GetConfigurationSettingValue("Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString"));

            DiagnosticMonitor.Start(cloudStorageAccount, config);
            Trace.Listeners.Add(new DiagnosticMonitorTraceListener());

            BowlusLogger.LogInfo("Configured Windows Azure Diagnostics");
        }
    }
}
